package com.bjpowernode.web.controller;

import com.bjpowernode.api.dto.UserAccountInfo;
import com.bjpowernode.api.dto.UserRechargeInfo;
import com.bjpowernode.api.model.User;
import com.bjpowernode.constants.Constant;
import com.bjpowernode.constants.RedisKey;
import com.bjpowernode.constants.enums.Code;
import com.bjpowernode.util.CommonUtils;
import com.bjpowernode.web.resp.ResponseObj;
import com.bjpowernode.web.resp.view.UserAccountView;
import com.bjpowernode.web.resp.view.UserRechargeView;
import com.bjpowernode.web.resp.vo.LoginUserParam;
import com.bjpowernode.web.resp.vo.RegisterUserParam;
import com.bjpowernode.web.util.UserUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author 麦翔盛
 * @ClassName: UserController
 * @Package: com.bjpowernode.web.controller
 * @description: 用户接口
 * @date 2022/5/21 16:47
 */

@Api(tags = "用户接口")
@RestController
public class UserController extends BaseController {

    //eabd8ce9404507aa8c22714d3f5eada9
    @ApiOperation(value = "用户注册")
    @PostMapping("/v1/user/register")
    public ResponseObj userRegister(@RequestBody RegisterUserParam registerUserParam) {
        String phone = registerUserParam.getPhone();
        String originPassword = registerUserParam.getRegPassword();
        String code = registerUserParam.getCode();

        //校验手机号码格式是否正确
        if (!UserUtil.checkRegisterParam(registerUserParam)) {
            //请求参数错误
            return ResponseObj.error(Code.REQ_PARAM_FORMAT_ERR);
        }

        //判断验证码是否已经存在

        if (!smsService.checkRegCodeValid(phone, code)) {
            //验证码错误
            return ResponseObj.error(Code.CODE_ERROR);
        }

        //添加用户
        int regResult = userService.userRegister(phone, originPassword);
        if (regResult == 0) {
            //参数错误
            return ResponseObj.error(Code.REQ_PARAM_FORMAT_ERR);
        } else if (regResult == 2) {
            return ResponseObj.error(Code.USER_EXIST);
        }

        return ResponseObj.ok();

    }


    /**
     * 用户登录
     *
     * @param userParam 用户登录参数
     */
    @ApiOperation("用户登录")
    @PostMapping("v1/user/login")
    public ResponseObj userLogin(@RequestBody LoginUserParam userParam, HttpServletRequest request) {

        ResponseObj result = ResponseObj.fail();
        //校验参数
        if (UserUtil.checkUserLoginParam(userParam)) {
            //将数据取出
            String phone = userParam.getPhone();
            String password = userParam.getLogPassword();
            String code = userParam.getCode();

            //判断验证码是否正确
            if (!smsService.checkLoginCodeValid(phone, code)) {
                return ResponseObj.error(Code.CODE_ERROR);
            }

            //用户是否存在
            boolean exist = userService.userExist(phone);
            if (!exist) {
                return ResponseObj.error(Code.USER_EXIST);
            }

            //判断用户和密码是否正确
            User loginUser = userService.userLogin(phone, password);
            if (loginUser == null) {
                return ResponseObj.error(Code.LOGIN_USER_PASSWORD_ERROR);
            }

            //生成token
            String accessToken = CommonUtils.getRandomToken();
            String key = RedisKey.ACCESS_TOKEN + accessToken;
            //创建存放token数据的map
            Map<String, Object> tokenData = new HashMap<>(3);
            tokenData.put("uid", String.valueOf(loginUser.getId()));
            tokenData.put("create", DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            tokenData.put("ip", request.getRemoteAddr());
            // 存放到redis中
            BoundHashOperations<String, Object, Object> opts = stringRedisTemplate.boundHashOps(key);
            opts.putAll(tokenData);
            opts.expire(60, TimeUnit.MINUTES);

            //创建返回到客户端的数据
            Map<String, Object> respObj = new HashMap<>(3);
            respObj.put("uid", loginUser.getId());
            respObj.put("name", loginUser.getName());
            respObj.put("phone", loginUser.getPhone());
            respObj.put("accessToken", accessToken);

            return ResponseObj.ok().content(respObj);

        } else {
            result.setEnum(Code.REQ_PARAM_FORMAT_ERR);
        }

        return result;
    }


    /**
     * 用户登出
     *
     * @param authorization 权限认证头
     */
    @ApiOperation("用户登出")
    @GetMapping("/v1/user/logout")
    public ResponseObj userLogOut(@RequestHeader("Authorization") String authorization) {
        //判空
        if (StringUtils.isBlank(authorization)
                || !authorization.startsWith(Constant.HEADER_BEARER)) {
            return ResponseObj.fail();
        }
        //取出token
        String token = authorization.substring(Constant.TOKEN_START_INDEX);
        if (StringUtils.isNotBlank(token)) {

            //从redis中取出
            String tokenKey = RedisKey.ACCESS_TOKEN + token;
            boolean delete = stringRedisTemplate.delete(tokenKey);
            if (delete) {
                //判断token删除成功
                return ResponseObj.ok();
            }
        }
        return ResponseObj.error(Code.USER_LOGOUT_FAIL);
    }


    /**
     * 实名认证
     *
     * @param uid  用户id 通过请求头传过来
     * @param name 用户真实姓名
     * @param idNo 用户身份证号码
     */
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "实名认证")
    @PostMapping("/v1/user/realname")
    public synchronized ResponseObj realName(@RequestHeader(value = "uid") Integer uid,
                                             @RequestParam("name") String name,
                                             @RequestParam("idNo") String idNo) {
        //校验数据格式 拦截器会验证是否有uid
        if (uid == null || uid == 0 || !StringUtils.isNoneBlank(name, idNo)) {
            //有数据为空
            return ResponseObj.error(Code.REQ_PARAM_FORMAT_ERR);
        }

        //查询该用户是否存在
        if (userService.queryUserById(uid) == null) {
            //用户不存在
            return ResponseObj.error(Code.USER_ID_NOT_EXIST);
        }

        //查该uid是否已经通过实名认证
        boolean isVerified = userService.isVerifiedRealName(uid);

        if (isVerified) {
            //用户已经实名认证通过
            return ResponseObj.error(Code.REAL_NAME_IS_VERIFIED);
        }

        //判断是否实名认证通过
        try {
            boolean isPass = realNameService.verifiedRealName(name, idNo);

            if (!isPass) {
                //实名认证不通过
                return ResponseObj.error(Code.REAL_NAME_VERIFIED_FAIL);
            }

            //将实名 和 身份证号码 数据放入数据库中
            userService.updateUserRealInfo(uid, name, idNo);

            return ResponseObj.ok();

        } catch (Exception e) {
            //实名认证发生异常
            ResponseObj.error(Code.REAL_NAME_VERIFIED_ERROR);
            e.printStackTrace();
        }

        return ResponseObj.fail();

    }

    /**
     * 查询用户的账户信息
     * @param uid 用户id
     */
    @ApiOperation(value = "查询用户的账户信息")
    @GetMapping("/v1/user/info")
    public ResponseObj getUserAccountInfo(@RequestHeader("uid") Integer uid) {
        ResponseObj result = ResponseObj.ok();
        if (uid != null && uid > 0) {
            UserAccountInfo userAccount = userService.queryUserAccountInfoById(uid);
            UserAccountView userAccountView = new UserAccountView(userAccount);
            return result.content(userAccountView);
        }
        return result;
    }

    /**
     * 查询用户充值记录
     * @param uid 用户id
     * @param pageNo 页码
     * @param pageSize 限制条数
     */
    @ApiOperation(value = "用户充值记录")
    @GetMapping("/v1/user/rechargeinfo")
    public ResponseObj getUserRechargeList(@RequestHeader("uid") Integer uid,
                                           @RequestParam("pageNo") Integer pageNo,
                                           @RequestParam("pageSize")Integer pageSize){
        ResponseObj result = ResponseObj.ok();
        if (uid != null && uid > 0){
            pageNo = CommonUtils.getDefPageNo(pageNo);
            pageSize = CommonUtils.getDefPageSize(pageSize);
            List<UserRechargeInfo> userRechargeList = userService.queryUserRechargeInfoByUid(uid, pageNo, pageSize);

            List<UserRechargeView> viewList = new ArrayList<>();
            //dto -> view
            userRechargeList.forEach(userRechargeInfo -> viewList.add(new UserRechargeView(userRechargeInfo)));


            return result.content(viewList);
        }
        return result;
    }
}







